package org.znxs.znxsojjudge;

import cn.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.znxs.common.common.ErrorCode;
import org.znxs.common.exception.BusinessException;
import org.znxs.model.model.dto.question.JudgeCase;
import org.znxs.model.model.entity.Question;
import org.znxs.model.model.entity.QuestionSubmit;
import org.znxs.model.model.enums.QuestionSubmitStatusEnum;
import org.znxs.model.model.judge.ExecuteCodeRequest;
import org.znxs.model.model.judge.ExecuteCodeResponse;
import org.znxs.model.model.judge.JudgeInfo;
import org.znxs.model.model.vo.QuestionSubmitVO;
import org.znxs.znxsojjudge.codeSandbox.CodeSandbox;
import org.znxs.znxsojjudge.codeSandbox.CodeSandboxFactory;
import org.znxs.znxsojjudge.codeSandbox.CodeSandboxProxy;
import org.znxs.znxsojjudge.strategy.JudgeContext;
import org.znxs.znxsojservice.services.QuestionFeignClient;


import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class JudgeServiceImpl implements JudgeService {


    @Resource
    private QuestionFeignClient questionFeignClient;

    @Resource
    private JudgeManager judgeManager;

    @Value("${codesandbox.type:example}")
    private String type;


    @Override
    public QuestionSubmitVO doJudge(Long questionSubmitId) {
        // 非空判断
        if (questionSubmitId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 查询题目
        QuestionSubmit questionSubmit = questionFeignClient.getSubmitById(questionSubmitId);
        // 校验
        if (questionSubmit == null) {
            // 若题目不存在
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "提交信息不存在");
        }
        Long questionId = questionSubmit.getQuestionId();
        Question question = questionFeignClient.getById(questionId);
        if (question == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }

        // 2) 若题目为等待中，直接截断
        if (!questionSubmit.getStatus().equals(QuestionSubmitStatusEnum.WAITING.getValue())) {
            // 题目正在判题中或者为别的
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态错误");
        }

        // 3) 更改题目状态（判题中），防止重复提交
        QuestionSubmit updateQuestionSubmit = new QuestionSubmit();
        updateQuestionSubmit.setId(questionSubmitId);
        updateQuestionSubmit.setStatus(QuestionSubmitStatusEnum.RUNNING.getValue());
        boolean update = questionFeignClient.updateById(updateQuestionSubmit);
        if (!update) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");
        }

        // 4) 调用沙箱进行判题
        CodeSandbox codeSandbox = CodeSandboxFactory.newInstance(type);
        codeSandbox = new CodeSandboxProxy(codeSandbox);
        String language = questionSubmit.getLanguage();
        String code = questionSubmit.getCode();
        // 获取输入用例
        String judgeCaseStr = question.getJudgeCase();
        List<JudgeCase> judgeCaseList = JSONUtil.toList(judgeCaseStr, JudgeCase.class);
        List<String> inputList = judgeCaseList.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder().code(code).language(language).inputList(inputList).build();
        ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);

        List<String> outputList = executeCodeResponse.getOutputList();

        // 5) 根据沙箱执行结果，设置题目状态
        JudgeContext judgeContext = new JudgeContext();
        judgeContext.setJudgeInfo(executeCodeResponse.getJudgeInfo());
        judgeContext.setJudgeCaseList(judgeCaseList);
        judgeContext.setInputList(inputList);
        judgeContext.setQuestion(question);
        judgeContext.setOutputList(outputList);
        judgeContext.setQuestionSubmit(questionSubmit);
        JudgeInfo judgeInfo = judgeManager.doJudge(judgeContext);

        // 6） 修改数据库判题状态以及结果
        updateQuestionSubmit = new QuestionSubmit();
        updateQuestionSubmit.setId(questionSubmitId);
        updateQuestionSubmit.setStatus(QuestionSubmitStatusEnum.SUCCESS.getValue());
        updateQuestionSubmit.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));

        update = questionFeignClient.updateById(updateQuestionSubmit);

        if (!update) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");
        }
        QuestionSubmit questionSubmitResult = questionFeignClient.getSubmitById(updateQuestionSubmit.getId());

        return QuestionSubmitVO.objToVo(questionSubmitResult);
    }
}
